import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * Manager class for relational operations.
 * 
 * @author Sean Clapp
 * 
 */
public class AlgorithmManager {

	public AlgorithmManager() {

	}

	@SuppressWarnings("unchecked")
	public void removeRedundantRelations(RelationHolder newRelHolder) {
		for (int j = 0; j < newRelHolder.getRelationHolder().size(); j++) {
			String rName = "R" + j;
			for (int k = 0; k < newRelHolder.getRelationHolder().size(); k++) {
				String r2Name = "R" + k;
				// don't check against the same relation :P
				if (j != k) {
					try {
						if (newRelHolder
								.getRelation(rName)
								.getSetOfAllAttribs()
								.containsAll(
										newRelHolder.getRelation(r2Name)
												.getSetOfAllAttribs())) {
							newRelHolder.getRelationHolder().remove(r2Name);
							k--;
							j--;
						}
					} catch (NullPointerException e) {
						// e.printStackTrace();
					}
				}
			}
		}
	}

	/**
	 * Will check a relation to see if it contains a FD with multivalued
	 * dependency
	 * 
	 * @param r
	 *            - Relation to be checkd for mvds
	 * @return true if r contains a mvd
	 */
	public boolean containsMVD(Relation r) {
		for (int i = 0; i < r.getRelation().size(); i++) {
			if (r.getRelation().get(i).isMultiVal()) {
				return true;
			}
		}
		return false;
	}

	/**
	 * returns a copy of relation r1
	 * 
	 * @param r1
	 * @param r2
	 */
	@SuppressWarnings("rawtypes")
	public Relation copyRelation(Relation r1) {
		Relation r2 = new Relation();

		for (int i = 0; i < r1.getRelation().size(); i++) {
			FunctionalDependency fd = r1.getRelation().get(i);
			Set key = fd.getKey();
			Set value = fd.getValue();

			FunctionalDependency temp = new FunctionalDependency();
			temp.setKey(key);
			temp.setValue(value);
			if (fd.isMultiVal()) {
				temp.setMultiVal(true);
			}
			r2.getRelation().add(temp);
		}

		return r2;
	}

	/**
	 * Perform a deep fopy of a FunctionalDependency
	 * 
	 * @param fd
	 *            - the fd to be copied
	 * @return a FunctionalDependency object that is a copy of fd
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public FunctionalDependency copyFuncDepDeep(FunctionalDependency fd) {
		FunctionalDependency fd2 = new FunctionalDependency();

		Iterator it = fd.getKey().iterator();
		while (it.hasNext()) {
			String s = it.next().toString();
			fd2.getKey().add(s);
		}
		Iterator it2 = fd.getValue().iterator();
		while (it2.hasNext()) {
			String s = it2.next().toString();
			fd2.getValue().add(s);
		}

		return fd2;
	}

	/**
	 * Builds the cannonicalform of the given universal relation and stores it
	 * into the relationHolder object under the key "CanonicalForm"
	 * 
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public Relation buildCanonicalForm(Relation r) {
		Relation canForm = new Relation();
		canForm.setRelationName("Canonical Form");
		for (int i = 0; i < r.getRelation().size(); i++) {
			FunctionalDependency fd = r.getRelation().get(i);

			// for each key/values in the fd, get the attributes and break them
			// apart into canonical form
			Set key = fd.getKey();
			Set value = fd.getValue();

			// add new fd to canform relation for each attrib on the rigt side
			// of an FD in the UR
			Object[] a = value.toArray();
			for (int j = 0; j < value.size(); j++) {
				String attrib = a[j].toString();
				FunctionalDependency temp = new FunctionalDependency();

				Set tempList = new HashSet();
				String s = "" + attrib;
				tempList.add(s);

				temp.setKey(key);
				temp.setValue(tempList);
				canForm.getRelation().add(temp);
			}
		}
		return canForm;
	}

	/*
	 * Builds the minimal set of the relation of the given universal relation
	 * and stores it into the RelationHolder object under the key "MinimalSet".
	 * This also calls generateKey() to build the key of the minimal set and
	 * store it.
	 * 
	 * @param r
	 * 
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public Relation buildMinimalSet(Relation r) {

		if (containsMVD(r)) {
			System.out
					.println("Sorry, that relation has an MVD, you may only select 4NF (#3)");
			return r;
		}
		// copy the canonicalform of the relation to be used in the reduction of
		// the set to minimal
		Relation minimalSet = copyRelation(r);
		minimalSet.setRelationName("Minimal Set");
		// get the FD to be checked for closure. For each individual element in
		// the FD, if
		// it's redundant then remove it
		for (int i = 0; i < minimalSet.getRelation().size(); i++) {
			FunctionalDependency f = minimalSet.getRelation().get(i);

			// set the current fd to blank so that it doesn't get used.
			minimalSet.getRelation().set(i, getBlankFD());

			// iterate through the attributes in the key, for each attribute
			// check for the closure (in the minimal set(the set being updated
			// as the redundancies are found))
			int j = 0;
			while ((f.getKey().size() > 1) && (j < f.getKey().size())) {
				Iterator it = f.getKey().iterator();
				// build array or string from set to manipulate
				String[] st = new String[f.getKey().size()];
				int m = 0;
				while (it.hasNext()) {
					st[m] = it.next().toString();
					m++;
				}
				String b = st[j];
				// st = x-B...
				st[j] = "";

				Set xMinusB = new HashSet();
				Set origXminusB = new HashSet();
				for (int o = 0; o < st.length; o++) {
					if (st[o] != "") {
						xMinusB.add(st[o]);
						origXminusB.add(st[o]);
					}
				}// end for loop (o)

				// if (x-b)+ can reach y (without b), then set the key to (x-b)
				if (fclosure(xMinusB, minimalSet, f.getValue())) {
					f.setKey(xMinusB);
					f.setValue(f.getValue());
				} else {
					j++;
				}

			}// end while loop

			minimalSet.getRelation().set(i, f);

		}// end for loop(i)

		// now check each to see if the entire left side closure(instead of just
		// one attrib) can determine y to remove the entire FD
		int k = 0;
		while (k < minimalSet.getRelation().size()) {
			FunctionalDependency f = minimalSet.getRelation().get(k);
			minimalSet.getRelation().remove(k);

			Iterator it = f.getKey().iterator();
			String[] st = new String[f.getKey().size()];
			// build the string array that will hold the attributes involved
			// (used for calculating closure
			int m = 0;
			while (it.hasNext()) {
				st[m] = it.next().toString();
				m++;
			}

			Set x = new HashSet();
			for (int o = 0; o < st.length; o++) {
				if (st[o] != "") {
					x.add(st[o]);
				}
			}// end for loop (o)

			if (fclosure(x, minimalSet, f.getValue())) {

			} else {
				minimalSet.getRelation().add(k, f);
				k++;
			}
		}
		return minimalSet;
	}

	/**
	 * This will build a set of relations in 3nf. Takes a Set of relations and
	 * returns a set of relation in 3nf.
	 * 
	 * @param rh
	 *            - relationHolder object containing the relation/its
	 *            key/minnimal+canonicalforms
	 * @return the relationholder object which will be a collection of relations
	 *         expressed in 3nf form;
	 */
	@SuppressWarnings("unchecked")
	public RelationHolder build3NF(RelationHolder rh) {

		// step1 - minimal set (done elsewhere)
		// step2 - get key (done elsewhere)
		RelationHolder newRelHolder = new RelationHolder("Third Normal Form");
		Relation r = null;
		String relName;

		// go through the list of FDs, create new relations. check each FD
		// against every other FD for identical keys. if keys match, then those
		// FD values can be put into that relation
		for (int i = 0; i < rh.getRelation("MinimalSet").getRelation().size(); i++) {
			relName = "R" + i;
			// fd = the ith FD in minimalset relation
			FunctionalDependency fd = rh.getRelation("MinimalSet")
					.getRelation().get(i);

			r = new Relation();
			r.setRelationName(relName);
			r.getRelation().add(fd);
			r.generateSetOfAllAttribs();

			// go through the list of FDs and see if any keys match.
			for (int j = 0; j < rh.getRelation("MinimalSet").getRelation()
					.size(); j++) {
				FunctionalDependency checkFD = rh.getRelation("MinimalSet")
						.getRelation().get(j);
				// if we're not comparing the same set :P
				if (i != j) {
					// if the key of the checkFD is the same as the fd we're
					// working with, then add that FD to the relation
					if (checkFD.getKey().equals(fd.getKey())) {
						r.getRelation().add(checkFD);
					}
				} else {
					// don't do anything, maybe.
				}
			}
			// update the list of attributes
			r.generateSetOfAllAttribs();

			// put into the relation holder the new relation containing the ith
			// FDs
			newRelHolder.getRelationHolder().put(relName, r);
		} // end for i loop (don't populate the newRelHolder with relations

		// step 4 - if the key isn't fix it.
		// check for the key, if it's not found create a new relation to
		// house the key and add it to the newRelHolder
		boolean keyIncluded = false;
		for (Relation rel : newRelHolder.getRelationHolder().values()) {
			for (int i = 0; i < rel.getRelation().size(); i++) {
				if (rel.getRelation().get(i).getKey()
						.containsAll(rh.getRelation("MinimalSet").getKey())) {
					keyIncluded = true;
				}
			}
		}

		if (keyIncluded) {
			System.out.println("Key is included in the set of Relations, OK!");
		} else {
			Relation pkRel = new Relation();
			pkRel.setRelationName("RelationPK");
			pkRel.setKey(rh.getRelation("MinimalSet").getKey());
			FunctionalDependency fd = new FunctionalDependency();
			fd.setKey(rh.getRelation("MinimalSet").getKey());
			pkRel.getRelation().add(fd);
			pkRel.generateSetOfAllAttribs();
			newRelHolder.getRelationHolder().put("RelationPK", pkRel);
		}

		// step 5 check to see if any other relations can be consolodated
		// (remove any redundant FDs)
		for (int j = 0; j < newRelHolder.getRelationHolder().size(); j++) {
			String rName = "R" + j;
			for (int k = 0; k < newRelHolder.getRelationHolder().size(); k++) {
				String r2Name = "R" + k;
				// don't check against the same relation :P
				if (j != k) {
					try {
						if (newRelHolder
								.getRelation(rName)
								.getSetOfAllAttribs()
								.containsAll(
										newRelHolder.getRelation(r2Name)
												.getSetOfAllAttribs())) {
							// if the subset is found, add the FDs and remove
							// the additional one
							// (r2Name, and j--;
							for (int l = 0; l < newRelHolder
									.getRelationHolder().get(r2Name)
									.getRelation().size(); l++) {
								// if the FD doesn't exist in rName yet, then
								// add
								// it...
								if (!newRelHolder
										.getRelationHolder()
										.get(rName)
										.getRelation()
										.contains(
												newRelHolder
														.getRelationHolder()
														.get(r2Name)
														.getRelation().get(l))) {
									newRelHolder
											.getRelationHolder()
											.get(rName)
											.getRelation()
											.add(newRelHolder
													.getRelationHolder()
													.get(r2Name).getRelation()
													.get(l));
								}
							}
							newRelHolder.getRelationHolder().remove(r2Name);
							k--;
							j--;
						}
					} catch (NullPointerException e) {
						// e.printStackTrace();
					}
				}
			}
		}
		for (Relation x : newRelHolder.getRelationHolder().values()) {
			x.generateSetOfAllAttribs();
		}
		return newRelHolder;
	}

	/*
	 * 
	 * This will determine if a collection of relations (Q(Uq,Fq)) is in BCNF
	 * form. (Pass in a minimal set)
	 * 
	 * step1) get minimal cover of r (G)
	 * 
	 * step2) if there is an FD in G s.t. x+ in ref to G does not include Uq
	 * (set of all attribs) then Q is not in BCNF
	 * 
	 * @param r The Relation that is to be used to determine if BCNF or not
	 * (pass in a minimal cover)
	 * 
	 * @return true if given RelationHolder object rh is in BCNF, false
	 * otherwise
	 */
	public boolean isInBCNF(Relation r) {
		boolean isInBCNF = true;
		Relation canonical = buildCanonicalForm(r);
		canonical.generateSetOfAllAttribs();
		Relation minimalCover = buildMinimalSet(canonical);
		minimalCover.generateSetOfAllAttribs();

		for (int i = 0; i < minimalCover.getRelation().size(); i++) {
			if (!fclosure(minimalCover.getRelation().get(i).getKey(),
					minimalCover, minimalCover.getSetOfAllAttribs())) {
				isInBCNF = false;
				break;
			}
		}
		return isInBCNF;
	}

	/**
	 * Checks a RelationHolder object to see if all of the relations in it are
	 * in BCNF
	 * 
	 * @param rh
	 *            - The RelationHolder object to check and see if all Relations
	 *            in it are in BCNF
	 * @return true if all the relations in rh are in BCNF, false otherwise.
	 */
	public boolean allAreInBCNF(RelationHolder rh) {
		boolean allInBCNF = true;

		for (Relation r : rh.getRelationHolder().values()) {
			if (!r.getRelationName().equalsIgnoreCase("LostFDs")) {
				if (!isInBCNF(r)) {
					allInBCNF = false;
					break;
				}
			}
		}
		return allInBCNF;
	}

	/*
	 * 
	 * Pass in the minimal cover of a relation. set all bcnf to false, while
	 * !allBCNF0. Build BCNF form
	 * 
	 * @param r - the relation to be converted to BCNF
	 * 
	 * @return a relationholder object containing BCNF form of a relation
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public RelationHolder buildBCNF(Relation relation) {
		Relation r = copyRelation(relation);
		r.generateSetOfAllAttribs();
		r.setRelationName("R1");
		RelationHolder bcnf = new RelationHolder("BCNF");
		bcnf.getRelationHolder().put("R1", r);
		Relation lostFDs = new Relation();
		lostFDs.setRelationName("LostFDs");
		bcnf.getRelationHolder().put("LostFDs", lostFDs);

		int i = 1;
		try {
			while (!allAreInBCNF(bcnf)) {
				i++;
				String relName = "R" + i;
				// checking all FDs in r to see if any are not in bcnf
				// when one is found that isn't in BCNF, remove y, and create a
				// new relation
				try {
					Relation r1 = bcnf.getRelation("R1");
					// for (Relation r1 : bcnf.getRelationHolder().values()) {
					for (int j = 0; j < r1.getRelation().size(); j++) {
						if (!fclosure(r1.getRelation().get(j).getKey(), r1,
								r1.getSetOfAllAttribs())) {
							Relation rel = new Relation();
							rel.setRelationName(relName);
							FunctionalDependency fd = r1.getRelation().get(j);

							rel.getRelation().add(fd);
							rel.generateSetOfAllAttribs();
							bcnf.getRelationHolder().put(relName, rel);

							// remove the FD you just put into a new relation
							bcnf.getRelationHolder().get("R1").getRelation()
									.remove(j);
							// now remove y from the original
							try {
								for (int k = 0; k < bcnf.getRelationHolder()
										.get("R1").getRelation().size(); k++) {
									FunctionalDependency f = bcnf
											.getRelationHolder().get("R1")
											.getRelation().get(k);
									boolean alreadyRemoved = false;
									Iterator it = fd.getValue().iterator();

									while (it.hasNext()) {
										Object s = it.next();
										Set n = new HashSet();
										n.add(s);
										if (f.getKey().containsAll(n)
												&& !f.getValue().isEmpty()) {
											if (!alreadyRemoved) {
												FunctionalDependency lostfd = copyFuncDepDeep(f);
												lostFDs.getRelation().add(
														lostfd);
												lostFDs.generateSetOfAllAttribs();
												alreadyRemoved = true;
												k--;
											}
											f.getKey().removeAll(n);
											f.getKey().addAll(f.getValue());
											f.getValue()
													.removeAll(f.getValue());
											Relation rela = new Relation();
											rela.getRelation().add(f);
											rela.generateSetOfAllAttribs();
											i++;
											String relName2 = "R" + i;
											rela.setRelationName(relName2);
											bcnf.getRelationHolder().get("R1")
													.getRelation().remove(f);
											bcnf.getRelationHolder().put(
													relName2, rela);
										} else if (f.getValue().containsAll(n)) {
											if (!alreadyRemoved) {
												k--;
											}
											FunctionalDependency lostfd = copyFuncDepDeep(f);
											lostFDs.getRelation().add(lostfd);
											lostFDs.generateSetOfAllAttribs();
											alreadyRemoved = true;
											f.getValue().removeAll(n);
										} else if (f.getKey().containsAll(n)
												&& f.getValue().isEmpty()) {
											f.getKey().removeAll(n);
										}
									}
								}
							} catch (ArrayIndexOutOfBoundsException e) {
								// e.printStackTrace();
							}

							bcnf.getRelationHolder().get("R1")
									.generateSetOfAllAttribs();

							break;
						}
					}
					// }
				} catch (ConcurrentModificationException e) {
					e.printStackTrace();
				}
			}
		} catch (NullPointerException e) {
			e.printStackTrace();
		}

		removeRedundantRelations(bcnf);
		// recalculate the attributes, and remove redundant attributes.
		for (Relation x : bcnf.getRelationHolder().values()) {
			x.generateSetOfAllAttribs();
		}

		return bcnf;
	}

	/*
	 * Returns a RelationHolder object with relations in 4nf.
	 * 
	 * @param originalRelation - the original relation that will be used to
	 * compute the 4nf
	 * 
	 * @return a RelationHolder object with relations in 4nf
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public RelationHolder build4NF(RelationHolder originalRelation) {
		// create a copy of the original relation to work with.
		RelationHolder rh4NF = new RelationHolder("Fourth Normal Form");
		Relation universalRelation = copyRelation(originalRelation
				.getRelation("Universal"));
		universalRelation.setRelationName("R1");
		universalRelation.generateSetOfAllAttribs();
		rh4NF.getRelationHolder().put("R1", universalRelation);
		Relation lostFDs = new Relation();
		lostFDs.setRelationName("LostFDs");
		rh4NF.getRelationHolder().put("LostFDs", lostFDs);

		int i = 1;

		// check each ***non-trivial*** mvd of x>>y in Di
		for (int j = 0; j < universalRelation.getRelation().size(); j++) {
			FunctionalDependency fd = universalRelation.getRelation().get(j);

			// if non-trivial MVD
			if (fd.isMultiVal() && isNonTrivialMVD(universalRelation, fd)) {
				// if x is not a superkey of R, then
				// i=i+1
				i++;
				String rName = "R" + i;
				Relation rel = new Relation();
				rel.getRelation().add(fd);
				rel.generateSetOfAllAttribs();
				rel.setRelationName(rName);

				// replace R with Ri({x,y},{x>>y}) and R({U-y}, {D-(x>>y)})
				rh4NF.getRelationHolder().put(rName, rel);

				// take out all nontrivial mvds of R1, remove ys from R1, and
				// create
				universalRelation.getRelation().remove(j);

				// now remove y from the original
				try {
					for (int k = 0; k < universalRelation.getRelation().size(); k++) {
						
						FunctionalDependency f = universalRelation
								.getRelation().get(k);

						boolean alreadyRemoved = false;
						Iterator it = fd.getValue().iterator();
						try {
							do {
								Object s = it.next();
								Set n = new HashSet();
								n.add(s);
								
								if (f.getKey().containsAll(n)) {
									// if this value has already been removed,
									// there's no need to add it to the lostFD
									// list again, or decrement k
									if (!alreadyRemoved) {
										FunctionalDependency lostfd = copyFuncDepDeep(f);
										lostFDs.getRelation().add(lostfd);
										lostFDs.generateSetOfAllAttribs();
										alreadyRemoved = true;
										k--;
									}
									// remove the values of n from the key, then
									// create a new relation holding the new fd,
									// then put the relation into the relation
									// holder. (if we remove more attributes
									// because y has multiple attributes, we can
									// still remove from this FD and it will
									// update the relation.)
									f.getKey().removeAll(n);
									f.getKey().addAll(f.getValue());
									f.getValue().removeAll(f.getValue());
									Relation rela = new Relation();
									rela.getRelation().add(f);
									rela.generateSetOfAllAttribs();
									i++;
									String relName2 = "R" + i;
									rela.setRelationName(relName2);
									universalRelation.getRelation().remove(f);
									rh4NF.getRelationHolder().put(relName2,
											rela);
								} else if (f.getValue().containsAll(n)) {
									if (!alreadyRemoved) {
										k--;
									}
									FunctionalDependency lostfd = copyFuncDepDeep(f);
									lostFDs.getRelation().add(lostfd);
									lostFDs.generateSetOfAllAttribs();
									alreadyRemoved = true;
									f.getValue().removeAll(n);
								} else if (f.getKey().containsAll(n)
										&& f.getValue().isEmpty()) {
									f.getKey().removeAll(n);
								}
							} while (it.hasNext());
						} catch (ConcurrentModificationException e) {

						}
						
						universalRelation.generateSetOfAllAttribs();
						
					}
				} catch (ArrayIndexOutOfBoundsException e) {
				}

			} else {
				// do nothing...
			}
		}
		removeRedundantRelations(rh4NF);
		for (Relation r : rh4NF.getRelationHolder().values()) {
			r.generateSetOfAllAttribs();
		}
		return rh4NF;
	}

	/**
	 * Checks if an MVD is nontrivial input: Ri(Ui,Di) output: determine whether
	 * x>>y is a non-trivial MVD Trivial if one of the following if(xUy)=U
	 * if(y=null) if(y is subset of x) else - non trivial
	 * 
	 * @param r
	 *            - this is Ri
	 * @param mvd
	 *            - the mvd that is to be determined if it is non-trivial or not
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public boolean isNonTrivialMVD(Relation r, FunctionalDependency mvd) {
		boolean nonTrivial = true;

		// if any of those 3, then nonTrivial is false, and should be changed
		// if attribs in MVD contain all the attribs in the relation OR
		// if mvd y value is empty
		// if y is a subset of x
		Set s = new HashSet();
		s.addAll(mvd.getKey());
		s.addAll(mvd.getValue());
		if (s.containsAll(r.getSetOfAllAttribs()) || mvd.getValue().isEmpty()
				|| mvd.getKey().containsAll(mvd.getValue())) {
			nonTrivial = false;
		}
		return nonTrivial;
	}

	/**
	 * This will check if a MVD is a super key of R
	 * 
	 * @param r
	 *            - The relation to be used in determining if the mvd is a
	 *            superkey
	 * @param mvd
	 *            - The multivalue dependency that will be checked
	 * @return true if the mvd is a superkey of r.
	 */
	public boolean isSuperKeyOfR(Relation r, FunctionalDependency mvd) {
		// if x>Ui is inferred from Di
		// then x is a superkey of Ri
		// else x is not a superkey of Ri
		return false;
	}

	/**
	 * Takes a relation and builds the key of that relation, returning a set
	 * holding the attributes that are the key of the relation.
	 * 
	 * @param r
	 *            - The relation that you wish to find the key for
	 * @return the Set of attributes that is the key of r
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Set generatePrimaryKey(Relation r) {
		Set keySet = new HashSet();
		// createkey alg
		// key = u (key = set of all attribs)
		keySet.addAll(r.getSetOfAllAttribs());
		// for each attrib A, in K, do: compute (k-A)+ in ref to F;
		// if k-A contains U, then k=k-A;

		// build array or string from set to manipulate
		Iterator it = keySet.iterator();
		String[] keySetArray = new String[keySet.size()];
		int m = 0;
		while (it.hasNext()) {
			keySetArray[m] = it.next().toString();
			m++;
		}

		// build the k-a and run the fclosure on each, removing them if they're
		// redundant
		for (int i = 0; i < keySetArray.length; i++) {
			String a = keySetArray[i];
			keySetArray[i] = null;

			Set kMinusA = new HashSet();

			// build the kMinusA set to use in the fclosure
			for (int j = 0; j < keySetArray.length; j++) {
				// char c = a.charAt(j);
				// String n = "" + c;
				kMinusA.add(keySetArray[j]);
			}

			if (fclosure(kMinusA, r, r.getSetOfAllAttribs())) {
				// do nothing, the a has already been removed!
			} else {
				// return a to the keySetArray!
				keySetArray[i] = a;
			}
		}

		// after done removing unnessary attributes in the key, rebuild the
		// keySet Set with the keySetArray;
		Set key = new HashSet();
		for (int i = 0; i < keySetArray.length; i++) {
			if (keySetArray[i] != null) {
				String s = keySetArray[i];
				key.add(s);
			}
		}
		return key;
	}

	/**
	 * Checks to see if the set origXminusB can determine the set y through
	 * closure. If this returns true, this means that the closure of (x-b) is
	 * possible, so the new x (left side) of the FD will become (x-b)
	 * 
	 * @param origXminusB
	 *            - perform the closure of this. y must be a subset
	 * @param original
	 *            - The relation that this operation is performed upon. This is
	 *            the original relation minus the FD that is being checked for
	 *            closure
	 * @param y
	 *            - the "right side" of a FD that will be a subset of
	 *            origXminusB closure if this is to return true
	 * @return true if origXminusB^+ contains y. (y is a subset of the closure
	 *         of origXminusB
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private boolean fclosure(Set origXminusB, Relation original, Set y) {
		boolean closes = false;
		// create new set to hold all the values of the FD to check closure of
		Set xMinusB = new HashSet();

		xMinusB.addAll(origXminusB);

		for (int h = 0; h < original.getRelation().size(); h++) {
			for (int i = 0; i < original.getRelation().size(); i++) {
				FunctionalDependency f = original.getRelation().get(i);

				if (xMinusB.containsAll(f.getKey())) {
					xMinusB.addAll(f.getValue());
				}
				if (xMinusB.containsAll(y)) {
					closes = true;
					return closes;
				}
			}
		}
		return closes;
	}

	/**
	 * Provides a blank FD to be used
	 * 
	 * @return FunctionalDependency with no key or value
	 */
	@SuppressWarnings("rawtypes")
	public FunctionalDependency getBlankFD() {
		FunctionalDependency blankFD = new FunctionalDependency();
		Set blankAttribList = new HashSet();
		blankFD.setKey(blankAttribList);
		blankFD.setValue(blankAttribList);
		return blankFD;
	}

}
